/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.stimuliband.microphone;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import org.apache.log4j.Logger;

/**
 *
 * @author
 */
public class PlaySin {

    private static Logger logger = Logger.getLogger(PlaySin.class.getSimpleName());

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws LineUnavailableException, InterruptedException {
        // TODO code application logic here

        NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
        nf.setMaximumFractionDigits(1);
        nf.setMinimumFractionDigits(1);
        nf.setGroupingUsed(false);


        int SAMPLING_RATE = 8000;
        int SAMPLE_BITS = 8;
        int CHANNELS = 1;


        byte[] buffer = new byte[SAMPLING_RATE];

        AudioFormat gsm = new AudioFormat(SAMPLING_RATE, SAMPLE_BITS, CHANNELS, true, true);
        DataLine.Info outputInfo = new DataLine.Info(SourceDataLine.class, gsm, buffer.length * 5);
        SourceDataLine line = (SourceDataLine) AudioSystem.getLine(outputInfo);


        line.addLineListener(new LineListener() {
            @Override
            public void update(LineEvent event) {
                logger.debug("event: " + event);
            }
        });



        double volume = 40;



        logger.info("Start");
        line.open();
        line.start();
        logger.info("Before write: " + line.available());

        int x = 0;


        List<SinusOscilator> ins = new ArrayList<>();
        int harmonics = 10;
        for (int h = 1; h <= harmonics; h++) {
            ins.add(new SinusOscilator(118 * h, 30-h));
        }
        

        double[] signal = new double[buffer.length];
        double max = Double.MIN_VALUE;
        double min = Double.MAX_VALUE;
        for (int i = 0; i < buffer.length; i++, x++) {
            signal[i] = 0;
            for (SinusOscilator sin : ins) {
                signal[i] += sin.next(x);
            }

            if (signal[i] < min) {
                min = signal[i];
            }
            if (signal[i] > max) {
                max = signal[i];
            }
        }

        logger.info("min: " + nf.format(min));
        logger.info("max: " + nf.format(max));

        double deltaInput = Math.abs(min) + Math.abs(max);
        double deltaOut = Math.abs(Byte.MIN_VALUE) + Math.abs(Byte.MAX_VALUE);

        for (int i = 0; i < buffer.length; i++) {

            double operation = signal[i];
            if (operation < 0) {
                operation = operation * Byte.MIN_VALUE / min;
            }
            if (operation > 0) {
                operation = operation * Byte.MAX_VALUE / max;
            }

            logger.info("from " + signal[i] + " to " + operation);

            buffer[i] = (byte) (operation);
        }


        boolean active = true;
        while (active) {
            int written = line.write(buffer, 0, buffer.length);
            logger.info("After write: " + written);
        }


        logger.info("Before stop");
        line.stop();
        logger.info("After stop");
    }
}
